import path from 'path';
import turf from '../../../../ext/turf';
import axios from 'axios';
import configTool from '../../../com/configTool';
import readFromDB from '../Util/readFromDB';
import readFromNet from '../Util/readFromNet';
import saveToDB from '../Util/saveToDB';
import saveToFile from '../Util/saveToFile';
import initDB from '../Util/initDB';
import awaitWrap from '../../../lib/awaitWrap';
import TileUtil4326 from '../../../lib/TileTool/TileUtil4326';
import TileSet from '../../TileTool/TileSet';
import readFromDisk from '../Util/readFromDisk';

const World = require('./World.json');

let authority_ing = false;
const DBName = 'CesiumWorldTerrain';
const baseUrl = 'https://assets.ion.cesium.com/asset_depot/1/CesiumWorldTerrain/v1.2/';
const ext = '?extensions=octvertexnormals-watermask-metadata&v=1.2.0';
const Cesium = require('../../../../ext/Cesium-1.130/index.js');

let Authorization = '';
const defaultAccessToken = Cesium.Ion.defaultAccessToken;
const tileUtil4326 = new TileUtil4326();


interface terrainBox {
    startX: number;
    endX: number;
    startY: number;
    endY: number;
}

let CesiumTerrain = {
    async init() {
        await configTool.init();
        configTool.preservableONDB() && await initDB(DBName);
    },
    async ionAuthority() {
        if (authority_ing) {
            await new Promise((resolve) => {
                let timer = setInterval(() => {
                    if (!authority_ing) {
                        clearInterval(timer);
                        resolve(null);
                    }
                }, 100);
            });
        } else {
            authority_ing = true;
            let [err, data] = await awaitWrap(axios.get('https://api.cesium.com/v1/assets/1/endpoint?access_token=' + defaultAccessToken));
            if (data) {
                data = data.data;
                Authorization = 'Bearer ' + data.accessToken;
                console.log('获取令牌成功', data.accessToken);

            } else {
                console.log(Cesium.Ion.defaultAccessToken);
                console.log('获取令牌失败');
            }
            authority_ing = false;
        }
    },
    async getFileBuffer(url: string) {
        await this.init();

        let err, buffer, dataSource;
        let headers = {'Authorization': Authorization};

        let relativePath = '\\1\\' + url;
        let fileSavePath = path.join(configTool.appBasePath, `temp/fileOut/assets.cesium.com`, relativePath);

        // 从本地文件夹中获取文件
        [err, buffer, dataSource] = await readFromDisk({fileSavePath, err, buffer, dataSource});

        // 从数据库中获取文件
        [err, buffer, dataSource] = await readFromDB({DBName, relativePath, err, buffer, dataSource});

        // 从网络获取，并持久化存储
        if (!buffer) {
            // Authorization === '' && await this.ionAuthority();
            [err, buffer, dataSource] = await readFromNet({url: baseUrl + url + ext, headers, err, buffer, dataSource});
        }

        if (err?.state === 404) {
        } else if (err?.state === 503) {
            console.log('请求过于频繁，服务器拒绝响应');
        } else if (err?.state === 401) {
            console.log(err);
            console.log('重置 Cesium 地形资源的 令牌');
            Authorization = '';
        }

        buffer && dataSource !== 'DB' && configTool.preservableONDB() && saveToDB({
            DBName,
            relativePath,
            buffer
        }, true).then();
        buffer && dataSource === 'Net' && configTool.preservableONFile() && saveToFile(fileSavePath, buffer).then();

        return [err, buffer];
    },
    async getTileListByGeoJson(zoom: number, geoJson: any, layerJson: any) {
        await this.init();
        const tileUtil4326 = new TileUtil4326();

        if (zoom === 0) {
            const tileSet = new TileSet();
            tileSet.add(0, 0, 0);
            tileSet.add(1, 0, 0);
            return {
                tileList: tileSet.getAll(),
                boxList: [{
                    'type': 'Feature',
                    'bbox': [-180, -90, 180, 90],
                    'properties': {},
                    'geometry': {
                        'type': 'Polygon',
                        'coordinates': [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
                    }
                }],
                effectiveAreaRangeList: [{'endX': 1, 'endY': 0, 'startX': 0, 'startY': 0}]
            };
        } else {
            geoJson = geoJson || World;
        }


        if (!layerJson) {
            const [err, buffer] = await CesiumTerrain.getFileBuffer('layer.json');
            layerJson = buffer ? JSON.parse(buffer.toString()) : null;
            if (err || layerJson === null) {
                return {tileList: [], boxList: []};
            }
        }


        const dataRanges = layerJson.available;

        const tileSet = new TileSet();
        const boxList: any[] = [];
        const areaRangeList = dataRanges[zoom];
        const effectiveAreaRangeList: terrainBox[] = [];
        for (let i = 0; i < areaRangeList?.length; i++) {
            // 原始数据的边界范围
            const rowAreaRange = areaRangeList[i];

            const rowMinTile = tileUtil4326.tileXYZToRectanglePolygon(rowAreaRange.startX, rowAreaRange.startY, zoom);
            const rowMaxTile = tileUtil4326.tileXYZToRectanglePolygon(rowAreaRange.endX, rowAreaRange.endY, zoom);
            // 数据区
            const rowAreaBbox = turf.bbox(turf.featureCollection([rowMinTile, rowMaxTile]));
            const rowAreaBoxPolygon = turf.bboxPolygon(rowAreaBbox);


            if (turf.booleanDisjoint(geoJson, rowAreaBoxPolygon)) {
                continue;
            }

            // 裁切区
            const polygons: any = [];
            turf.featureEach(geoJson, function (currentFeature: any) {
                if (currentFeature.geometry.type === 'Polygon') {
                    polygons.push(currentFeature.geometry.coordinates);
                }
            });

            const multiPoly = turf.multiPolygon(polygons);

            const clipGeoJson = turf.bboxClip(multiPoly, rowAreaBbox);
            const clipBbox = turf.bbox(clipGeoJson);

            const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
            const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);
            const trimRowAreaRange = {
                endX: Math.min(trimMaxTile.x, rowAreaRange.endX),
                endY: Math.min(trimMaxTile.y, rowAreaRange.endY),
                startX: Math.max(trimMinTile.x, rowAreaRange.startX),
                startY: Math.max(trimMinTile.y, rowAreaRange.startY)
            };

            const minX = Math.min(trimRowAreaRange.startX, trimRowAreaRange.endX);
            const maxX = Math.max(trimRowAreaRange.startX, trimRowAreaRange.endX, 0);
            const minY = Math.min(trimRowAreaRange.startY, trimRowAreaRange.endY);
            const maxY = Math.max(trimRowAreaRange.startY, trimRowAreaRange.endY, 0);

            trimRowAreaRange.startX = minX < 0 ? 0 : minX;
            trimRowAreaRange.endX = maxX;
            trimRowAreaRange.startY = minY < 0 ? 0 : minY;
            trimRowAreaRange.endY = maxY;

            const leafList = [];
            if (Math.abs(trimRowAreaRange.endX - trimRowAreaRange.startX) > 3 || Math.abs(trimRowAreaRange.endY - trimRowAreaRange.startY) > 3) {
                // 将原始边界拆分为 3X3 的 九 份
                const middle_1_3_X = trimRowAreaRange.startX + Math.floor((trimRowAreaRange.endX - trimRowAreaRange.startX) / 3) - 1;
                const middle_2_3_X = trimRowAreaRange.startX + Math.floor((trimRowAreaRange.endX - trimRowAreaRange.startX) / 3) * 2 - 1;
                const middle_1_3_Y = trimRowAreaRange.startY + Math.floor((trimRowAreaRange.endY - trimRowAreaRange.startY) / 3) - 1;
                const middle_2_3_Y = trimRowAreaRange.startY + Math.floor((trimRowAreaRange.endY - trimRowAreaRange.startY) / 3) * 2 - 1;

                const leafOne = {
                    startX: trimRowAreaRange.startX,
                    startY: trimRowAreaRange.startY,
                    endX: middle_1_3_X,
                    endY: middle_1_3_Y
                };
                const leafTwo = {
                    startX: middle_1_3_X + 1,
                    startY: trimRowAreaRange.startY,
                    endX: middle_2_3_X,
                    endY: middle_1_3_Y
                };
                const leafThree = {
                    startX: trimRowAreaRange.startX,
                    startY: middle_1_3_Y + 1,
                    endX: middle_1_3_X,
                    endY: middle_2_3_Y
                };
                const leafFour = {
                    startX: middle_1_3_X + 1,
                    startY: middle_1_3_Y + 1,
                    endX: middle_2_3_X,
                    endY: middle_2_3_Y
                };
                const leafFive = {
                    startX: middle_2_3_X + 1,
                    startY: trimRowAreaRange.startY,
                    endX: trimRowAreaRange.endX,
                    endY: middle_1_3_Y
                };
                const leafSix = {
                    startX: middle_2_3_X + 1,
                    startY: middle_1_3_Y + 1,
                    endX: trimRowAreaRange.endX,
                    endY: middle_2_3_Y
                };
                const leafSeven = {
                    startX: trimRowAreaRange.startX,
                    startY: middle_2_3_Y + 1,
                    endX: middle_1_3_X,
                    endY: trimRowAreaRange.endY
                };
                const leafEight = {
                    startX: middle_2_3_X + 1,
                    startY: middle_2_3_Y + 1,
                    endX: trimRowAreaRange.endX,
                    endY: trimRowAreaRange.endY
                };
                const leafNine = {
                    startX: middle_1_3_X + 1,
                    startY: middle_2_3_Y + 1,
                    endX: middle_2_3_X,
                    endY: trimRowAreaRange.endY
                };
                leafList.push(...[leafOne, leafTwo, leafThree, leafFour, leafFive, leafSix, leafSeven, leafEight, leafNine]);
            } else {
                leafList.push(trimRowAreaRange);
            }

            // console.log(zoom,leafList);

            for (let j = 0; j < leafList.length; j++) {
                const leafAreaRange = leafList[j];

                const minTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.startX, leafAreaRange.startY, zoom);
                const maxTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.endX, leafAreaRange.endY, zoom);
                // 数据区
                const areaBbox = turf.bbox(turf.featureCollection([minTile, maxTile]));
                const areaBoxPolygon = turf.bboxPolygon(areaBbox);

                if (!turf.booleanDisjoint(geoJson, areaBoxPolygon)) {

                    // 裁切区
                    const polygons: any = [];
                    turf.featureEach(geoJson, function (currentFeature: any) {
                        if (currentFeature.geometry.type === 'Polygon') {
                            polygons.push(currentFeature.geometry.coordinates);
                        }
                    });

                    const multiPoly = turf.multiPolygon(polygons);

                    const clipGeoJson = turf.bboxClip(multiPoly, areaBbox);
                    const clipBbox = turf.bbox(clipGeoJson);

                    const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
                    const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);

                    const areaRange = {
                        endX: Math.min(trimMaxTile.x, leafAreaRange.endX),
                        endY: Math.min(trimMaxTile.y, leafAreaRange.endY),
                        startX: Math.max(trimMinTile.x, leafAreaRange.startX),
                        startY: Math.max(trimMinTile.y, leafAreaRange.startY)
                    };
                    areaRange.startX = areaRange.startX < 0 ? 0 : areaRange.startX;
                    areaRange.startY = areaRange.startY < 0 ? 0 : areaRange.startY;
                    areaRange.endX = areaRange.endX < 0 ? 0 : areaRange.endX;
                    areaRange.endY = areaRange.endY < 0 ? 0 : areaRange.endY;

                    const minX = Math.min(areaRange.startX, areaRange.endX);
                    const maxX = Math.max(areaRange.startX, areaRange.endX, 0);
                    const minY = Math.min(areaRange.startY, areaRange.endY);
                    const maxY = Math.max(areaRange.startY, areaRange.endY, 0);

                    const areaRangeBox = turf.bboxPolygon(
                        turf.bbox(turf.featureCollection([
                            tileUtil4326.tileXYZToRectanglePolygon(areaRange.startX, areaRange.startY, zoom),
                            tileUtil4326.tileXYZToRectanglePolygon(areaRange.endX, areaRange.endY, zoom)
                        ]))
                    );

                    boxList.push(areaRangeBox);
                    effectiveAreaRangeList.push(areaRange);


                    // console.log(areaRange);
                    // console.log('裁切区1', areaRange);
                    for (let x = minX; x <= maxX; x++) {
                        for (let y = minY; y <= maxY; y++) {
                            tileSet.add(x, y, zoom);
                        }
                    }
                }
            }
        }


        return {tileList: tileSet.getAll(), boxList, effectiveAreaRangeList};
    },

    clipLevelTileBBox(zoom: number, terrainBoxes: terrainBox[], geoJson: any = World) {
        const tileSet = new TileSet();
        const boxList: any[] = [];
        const effectiveAreaRangeList: terrainBox[] = [];
        const dataAreaRangeList: terrainBox[] = [];
        for (let j = 0; j < terrainBoxes.length; j++) {
            const leafAreaRange = terrainBoxes[j];

            const minTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.startX, leafAreaRange.startY, zoom);
            const maxTile = tileUtil4326.tileXYZToRectanglePolygon(leafAreaRange.endX, leafAreaRange.endY, zoom);

            // 数据区
            const areaBbox = turf.bbox(turf.featureCollection([minTile, maxTile]));
            const areaBoxPolygon = turf.bboxPolygon(areaBbox);

            dataAreaRangeList.push(areaBoxPolygon);


            if (!turf.booleanDisjoint(geoJson, areaBoxPolygon)) {

                // 裁切区
                const polygons: any = [];
                turf.featureEach(geoJson, function (currentFeature: any) {
                    if (currentFeature.geometry.type === 'Polygon') {
                        polygons.push(currentFeature.geometry.coordinates);
                    }
                });

                const multiPoly = turf.multiPolygon(polygons);

                const clipGeoJson = turf.bboxClip(multiPoly, areaBbox);
                const clipBbox = turf.bbox(clipGeoJson);

                const trimMinTile = tileUtil4326.getTileXYZ(clipBbox[0], clipBbox[1], zoom);
                const trimMaxTile = tileUtil4326.getTileXYZ(clipBbox[2], clipBbox[3], zoom);

                const areaRange = {
                    endX: Math.min(trimMaxTile.x, leafAreaRange.endX),
                    endY: Math.min(trimMaxTile.y, leafAreaRange.endY),
                    startX: Math.max(trimMinTile.x, leafAreaRange.startX),
                    startY: Math.max(trimMinTile.y, leafAreaRange.startY)
                };
                areaRange.startX = areaRange.startX < 0 ? 0 : areaRange.startX;
                areaRange.startY = areaRange.startY < 0 ? 0 : areaRange.startY;
                areaRange.endX = areaRange.endX < 0 ? 0 : areaRange.endX;
                areaRange.endY = areaRange.endY < 0 ? 0 : areaRange.endY;



                // const minX = Math.min(areaRange.startX, areaRange.endX);
                // const maxX = Math.max(areaRange.startX, areaRange.endX, 0);
                // const minY = Math.min(areaRange.startY, areaRange.endY);
                // const maxY = Math.max(areaRange.startY, areaRange.endY, 0);

                const areaRangeBox = turf.bboxPolygon(
                    turf.bbox(turf.featureCollection([
                        tileUtil4326.tileXYZToRectanglePolygon(areaRange.startX, areaRange.startY, zoom),
                        tileUtil4326.tileXYZToRectanglePolygon(areaRange.endX, areaRange.endY, zoom)
                    ]))
                );

                boxList.push(areaRangeBox);
                effectiveAreaRangeList.push(areaRange);

                const redundantStartX = areaRange.startX - 4;
                const redundantEndX = areaRange.endX + 4;
                const redundantStartY = areaRange.startY - 4;
                const redundantEndY = areaRange.endY + 4;

                for (let x = redundantStartX || 0; x <= redundantEndX; x++) {
                    for (let y = redundantStartY || 0; y <= redundantEndY; y++) {
                        tileSet.add(x, y, zoom);
                    }
                }
            }
        }


        return {tileList: tileSet.getAll(), boxList, effectiveAreaRangeList, dataAreaRangeList};
    }
};


export default CesiumTerrain;

